import json
import math
import time
import airsim
import numpy as np
import requests
from PyQt5.QtCore import QThread, pyqtSignal

# 这个是用来获取无人机的实时信息并将无人机的实时信息上传到海丰的Rabbitmq上
# 定义连接中航服API的类
class ConnectZCHF:
    def __init__(self):
        # 初始化API连接参数
        self.host_ip = "127.0.0.1"  # 主机IP地址
        self.content_type = "application/json"  # 请求内容类型
        self.secret = "b13d808ebe3a5e86699e7321803601bd"  # API密钥
        self.app_id = "dkp09usyqa2ghmu"  # 应用ID
        self.url = "https://api.hfga.com.cn/recevice/api/aircrafts/multiple"  # 无人机数据上报URL
        self.token_url = "https://api.hfga.com.cn/recevice/applicationAuth/getAccessToken"  # 获取访问令牌URL
        self.body_url = "https://api.hfga.com.cn/recevice/applicationAuth/getBodyForAppid/"  # 获取请求体URL
        self.access_token = ""  # 存储访问令牌
        self.sign = ""  # 存储签名信息
        self.body = ""  # 存储请求体

    def get_body(self):
        """获取API请求所需的签名和请求体"""
        header = {"host-ip": self.host_ip, "secret": self.secret}  # 请求头
        # 发送GET请求获取签名和请求体
        response = requests.get(self.body_url + self.app_id, headers=header)

        if response.status_code == 200:  # 请求成功
            datas = response.json()  # 解析JSON响应
            self.sign = datas['data']['sign']  # 提取签名
            self.body = datas['data']['body']  # 提取请求体
        else:
            print("请求失败，状态码：", response.status_code)  # 请求失败处理

    def get_token(self):
        """获取API访问令牌"""
        self.get_body()  # 先获取签名和请求体
        header = {"sign": self.sign, "appid": self.app_id}  # 包含签名的请求头
        Body = {"body": self.body}  # 请求体参数

        # 发送POST请求获取访问令牌
        response = requests.post(self.token_url, data=Body, headers=header)
        if response.status_code == 200:  # 请求成功
            datas = response.json()  # 解析JSON响应
            self.access_token = datas['data']  # 存储访问令牌
        else:
            print("请求失败，状态码：", response.status_code)  # 请求失败处理

    def send_jsons(self, json_data):
        """发送无人机数据到API"""
        self.get_token()  # 先获取访问令牌
        # 构建包含令牌的请求头
        header = {
            "accessToken": self.access_token,
            "appid": self.app_id,
            "Content-Type": self.content_type
        }
        jsons = json.dumps(json_data)  # 将Python对象转为JSON字符串
        # 发送POST请求上报数据
        response = requests.post(self.url, data=jsons, headers=header)
        if response.status_code != 200:  # 请求失败处理
            print("请求失败，状态码:", response.status_code)


# 定义获取无人机状态的线程类（继承自QThread）
class GetMultirotorState(QThread):
    # 定义信号，用于发射无人机状态数据
    multirotorstate_signal = pyqtSignal(dict)

    def __init__(self, vehicles):
        super().__init__()
        self.connect_zchf = ConnectZCHF()  # 创建API连接实例
        self.vehicles = vehicles  # 无人机名称列表

    def main_program(self):
        """主程序逻辑：持续获取并发送无人机状态"""
        client = airsim.MultirotorClient()  # 创建AirSim客户端
        while True:  # 无限循环
            if self.vehicles:  # 确保有无人机需要处理
                zchf_message = []  # 准备API上报数据
                emit_message = {}  # 准备信号发射数据

                # 遍历所有无人机
                for i, number in enumerate(self.vehicles):
                    dict = {}  # 单架无人机数据字典
                    zchf_message.append(dict)

                    # 填充无人机基本信息
                    zchf_message[i]["model"] = "solo"  # 无人机型号
                    zchf_message[i]["number"] = number  # 无人机编号
                    zchf_message[i]["device"] = 8  # 设备类型

                    # 从AirSim获取无人机状态
                    state = client.getMultirotorState(vehicle_name=number)

                    # 解析位置信息
                    latitude = state.gps_location.latitude  # 纬度
                    longitude = state.gps_location.longitude  # 经度
                    altitude = state.gps_location.altitude  # 海拔高度

                    # 解析速度信息
                    x_val = state.kinematics_estimated.linear_velocity.x_val
                    y_val = state.kinematics_estimated.linear_velocity.y_val
                    z_val = state.kinematics_estimated.linear_velocity.z_val
                    speed = math.sqrt(x_val * x_val + y_val * y_val)  # 水平速度

                    # 计算航向角（偏航角）
                    orientation = state.kinematics_estimated.orientation
                    euler_angles = np.array(
                        [orientation.w_val, orientation.x_val, orientation.y_val, orientation.z_val])
                    yaw = np.array(2 * np.arctan2(euler_angles[1], euler_angles[0]))
                    direction = np.degrees(yaw)  # 转为角度制

                    # 填充API数据
                    zchf_message[i]["direction"] = direction
                    zchf_message[i]["latitude"] = latitude
                    zchf_message[i]["longitude"] = longitude
                    zchf_message[i]["altitude"] = altitude
                    zchf_message[i]["speed"] = speed
                    zchf_message[i]["timestamp"] = state.timestamp  # 时间戳

                    # 填充信号发射数据
                    emit_message[number] = {}
                    emit_message[number]["latlng"] = [latitude, longitude]  # 经纬度
                    emit_message[number]["altitude"] = altitude  # 高度
                    emit_message[number]["horizon"] = speed  # 水平速度
                    emit_message[number]["vertical"] = z_val  # 垂直速度

                    # 当处理到最后一架无人机时
                    if i == len(self.vehicles) - 1:
                        self.connect_zchf.send_jsons(zchf_message)  # 发送数据到API
                        time.sleep(1)  # 等待1秒
                        # 通过信号发射数据
                        self.multirotorstate_signal.emit(emit_message)

    def run(self):
        """线程入口函数"""
        self.main_program()